package com.gis.controller;

import java.io.File;
import java.io.FileInputStream;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.gis.entity.LayerData;
import com.gis.result.ResponseResult;
import com.gis.service.LayerService;
import com.gis.utils.DirUtils;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.gis.service.DirectoryMonitorService;

@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/layer")
@Tag(name = "[产品]图层", description = "图层数据接口")
public class LayerController {

    @Autowired
    private LayerService layerService;
    @Autowired
    private DirectoryMonitorService directoryMonitorService;

    @Operation(summary = "上传文件", description = "上传文件")
    @PostMapping("/upload_file")
    @Transactional
    public ResponseResult<?> uploadFile(List<MultipartFile> files) {
        List<LayerData> savedLayerDatas = new ArrayList<>();
        try {
            for (MultipartFile file : files) {
                if (file.isEmpty()) {
                    throw new RuntimeException("文件不能为空");
                }
                LayerData layerData = layerService.fileNameAnalyse(file.getOriginalFilename());
                savedLayerDatas.add(layerService.uploadFile(layerData, file));
            }
        } catch (Exception e) {
            e.printStackTrace();
            Map<String, Object> map = Map.of(
                    "msg", "上传文件失败",
                    "code", 500,
                    "data", e.getMessage()
            ); 
            return ResponseResult.fail(map);
        }
        return ResponseResult.success(savedLayerDatas);
    }

    @Operation(summary = "添加存储仓库", description = "添加存储仓库")
    @PostMapping("/add_store")
    public ResponseResult<Map<String, Object>> addStore(String storename, String type,
            String originalFilename) {
        Map<String, Object> result = new HashMap<>();
        try {
            result = layerService.addStore(storename, type, originalFilename);
        } catch (Exception e) {
            e.printStackTrace();
            result.put("msg", "添加存储仓库失败");
            result.put("code", 500);
            result.put("data", e.getMessage());
            return ResponseResult.fail(result);
        }
        return ResponseResult.success(result);
    }

    @Operation(summary = "添加图层", description = "添加图层")
    @PostMapping("/add_layer")
    public ResponseResult<Map<String, Object>> addLayer(String storename, String layername,
            String nativeName, String originName) {
        Map<String, Object> result = new HashMap<>();
        try {
            result = layerService.addLayer(storename, layername, nativeName, originName);
        } catch (Exception e) {
            e.printStackTrace();
            result.put("msg", "添加图层失败");
            result.put("code", 500);
            result.put("data", e.getMessage());
            return ResponseResult.fail(result);
        }
        return ResponseResult.success(result);
    }

    @Operation(summary = "修改图层样式", description = "修改图层样式")
    @PostMapping("/modify_layer")
    public ResponseResult<Map<String, Object>> modifyLayer(String layername, String stylename) {
        Map<String, Object> result = new HashMap<>();
        try {
            result = layerService.modifyLayer(layername, stylename);
        } catch (Exception e) {
            e.printStackTrace();
            result.put("msg", "修改图层失败");
            result.put("code", 500);
            result.put("data", e.getMessage());
            return ResponseResult.fail(result);
        }
        return ResponseResult.success(result);
    }

    @Operation(summary = "保存文件并发布图层", description = "保存文件并在geoserver发布图层")
    @PostMapping("/publish_layer")
    @Parameters({ @Parameter(name = "layerData", description = "layer数据"),
            @Parameter(name = "file", description = "NetCDF文件"),
            @Parameter(name = "type", description = "NetCDF", required = false, example = "NetCDF"),
            @Parameter(name = "storename", description = "存储仓库名", required = false, example = "testStore"),
            @Parameter(name = "layername", description = "图层名", required = false, example = "testLayer"),
            @Parameter(name = "nativeName", description = "数据变量名", required = false, example = "data"),
            @Parameter(name = "stylename", description = "样式名称", required = false, example = "Normalize-0-1-Style") })
    public ResponseResult<?> publishLayer(LayerData _layerData, MultipartFile file,
            String type, String storename, String layername, String nativeName, String stylename) {

        try {
            LayerData layerData = layerService.publishLayer(_layerData, file, type, storename, layername,
                    nativeName, stylename);
            return ResponseResult.success(layerData);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            throw new RuntimeException("发布图层失败: " + e.getMessage());
        }
    }

    @Operation(summary = "保存文件发布图层(简化)", description = "保存文件并在geoserver发布图层")
    @PostMapping("/simple_publish_layer")
    @Parameters({ @Parameter(name = "file", description = "NetCDF文件"),
            @Parameter(name = "type", description = "NetCDF", required = false, example = "NetCDF"),
            @Parameter(name = "style", description = "样式名称", required = false, example = "Normalize-0-1-Style") })
    public ResponseResult<LayerData> simplePublishLayer(MultipartFile file, String type,
            String style) {
        LayerData layerData;
        try {
            layerData = layerService.publishLayer(file, type, style);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            throw new RuntimeException("发布图层失败: " + e.getMessage());
        }
        return ResponseResult.success(layerData);
    }

    @Operation(summary = "删除图层", description = "删除图层")
    @DeleteMapping("/delete_layer")
    public ResponseResult<Map<String, Object>> deleteLayer(String storename, String layername) {
        Map<String, Object> result = new HashMap<>();
        try {
            result = layerService.deleteLayer(storename, layername);
        } catch (Exception e) {
            e.printStackTrace();
            result.put("msg", "删除图层失败");
            result.put("code", 500);
            result.put("data", e.getMessage());
            return ResponseResult.fail(result);
        }
        return ResponseResult.success(result);
    }

    @Operation(summary = "删除存储仓库", description = "删除存储仓库")
    @DeleteMapping("/delete_store")
    public ResponseResult<Map<String, Object>> deleteStore(String storename) {
        HashMap<String, Object> result = new HashMap<>();
        try {
            result = layerService.deleteStore(storename);
        } catch (Exception e) {
            e.printStackTrace();
            result.put("msg", "删除存储仓库失败");
            result.put("code", 500);
            result.put("data", e.getMessage());
            return ResponseResult.fail(result);
        }
        return ResponseResult.success(result);
    }

    @Operation(summary = "获取图层列表", description = "获取图层列表")
    @GetMapping("/listLayer")
    public ResponseResult<List<LayerData>> getLayerList() {
        return ResponseResult.success("查询成功", layerService.list());
    }

    @Operation(summary = "获取筛选图层", description = "获取筛选图层")
    @GetMapping("/getFilterLayer")
    @Parameters({
            @Parameter(name = "satellite", description = "卫星", required = false, example = "GK2B"),
            @Parameter(name = "resolution", description = "分辨率", required = false, example = "05km"),
            @Parameter(name = "startTime", description = "开始时间", required = false, example = "2021-01-01 00:00:00"),
            @Parameter(name = "endTime", description = "结束时间", required = false, example = "2021-01-01 00:00:00"),
            @Parameter(name = "variableName", description = "变量名", required = false, example = "fog"),
            @Parameter(name = "dataLevel", description = "数据类型", required = false, example = "L1A"),
            @Parameter(name = "rangeList", description = "范围[最小X, 最小y,最大x, 最大y]", required = false, example = "114,21,125,33"),
            @Parameter(name = "fileType", description = "文件类型", required = false, example = "nc"), 
            @Parameter(name = "style", description = "样式名称", required = false, example = "fog") })
    public ResponseResult<List<LayerData>> getFilterLayer(
            @RequestParam(required = false) String satellite,
            @RequestParam(required = false) String resolution,
            @RequestParam(required = false) Timestamp startTime,
            @RequestParam(required = false) Timestamp endTime,
            @RequestParam(required = false) String variableName,
            @RequestParam(required = false) String dataLevel,
            @RequestParam(required = false) ArrayList<Float> rangeList,
            @RequestParam(required = false) String fileType,
            @RequestParam(required = false) String style) {
        QueryWrapper<LayerData> queryWrapper = new QueryWrapper<>();
        Map<String, Object> map = new HashMap<>();
        map.put("satellite", satellite);
        map.put("resolution", resolution);
        map.put("variable_name", variableName);
        map.put("data_level", dataLevel);
        map.put("file_type", fileType);
        map.put("style", style);
        queryWrapper.allEq(map, false);
        log.info("rangeList: " + rangeList);
        if (rangeList == null) {

            queryWrapper.between(startTime != null && endTime != null, "time", startTime, endTime);
            return ResponseResult.success("查询成功", layerService.list(queryWrapper));
        } else {
            try {
                if (rangeList.size() != 4) {
                    throw new Exception("rangeList size must be 4");
                }
                Float minX = rangeList.get(0);
                Float minY = rangeList.get(1);
                Float maxX = rangeList.get(2);
                Float maxY = rangeList.get(3);
                queryWrapper.between("min_x", minX, maxX);
                queryWrapper.between("min_y", minY, maxY);
                queryWrapper.between("max_x", minX, maxX);
                queryWrapper.between("max_y", minY, maxY);
                queryWrapper.between(startTime != null && endTime != null, "time", startTime,
                        endTime);
            } catch (Exception e) {
                e.printStackTrace();
                return ResponseResult.fail("rangeList size must be 4");
            }
        }

        return ResponseResult.success("查询成功", layerService.list(queryWrapper));
    }

    @Operation(summary = "获取范围", description = "获取范围")
    @Parameters({
            @Parameter(name = "url", description = "url", required = true, example = "http://localhost:8080/geoserver/rest/workspaces/test/coveragestores/test/coverages/test") })
    @GetMapping("/getRangeFromGeoserver")
    public ResponseResult<HashMap<String, Object>> getRangeFromGeoserver(String url) {
        HashMap<String, Object> result = new HashMap<>();
        try {
            result = layerService.GetRangeFromGeoserver(url);
        } catch (Exception e) {
            e.printStackTrace();
            result.put("msg", "获取范围失败");
            result.put("code", 500);
            result.put("data", e.getMessage());
            return ResponseResult.fail(result);
        }
        return ResponseResult.success(result);
    }

    @Operation(summary = "保存文件发布图层(超简化)", description = "保存文件并在geoserver发布图层")
    @PostMapping("super_simple_publishLayer")
    public ResponseResult<HashMap<String, Object>> super_simple_publishLayer(
            @RequestBody MultipartFile file) {
        try {
            layerService.publishLayer(file);
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseResult.fail("发布图层失败");
        }

        return ResponseResult.success("发布图层成功");
    }

    @Operation(summary = "下载文件", description = "获取文件")
    @GetMapping(value = "download_file")
    public void getFile(@RequestParam Long id, HttpServletResponse response) {
        LayerData layerData = layerService.getById(id);
        String pathName = layerData.getSavedDir() + '/' + layerData.getSavedName();
        File file = new File(pathName);
        switch (layerData.getFileType()) {
            case "nc":
                response.setContentType("application/octet-stream");
                break;
            case "png":
                response.setContentType("image/png");
                break;
            case "tif":
                response.setContentType("image/tiff");
                break;
            case "jpeg":
                response.setContentType("image/jpeg");
                break;
            default:
                break;
        }
        response.setHeader("Content-Disposition",
                "attachment; filename=" + layerData.getOriginName());
        try {
            FileInputStream fis = new FileInputStream(file);
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = fis.read(buffer)) > 0) {
                response.getOutputStream().write(buffer, 0, len);
            }
            fis.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Operation(summary = "获取文件", description = "获取文件")
    @Parameters({ @Parameter(name = "id", description = "文件ID", required = true, example = "1") })
    @GetMapping("get_file")
    public ResponseEntity<Resource> getFile(@RequestParam Integer id) {
        try {
            Resource resource = layerService.getFile(id);
            LayerData layerData = layerService.getById(id);
            MediaType mediaType = MediaType.APPLICATION_OCTET_STREAM;
            switch (layerData.getFileType()) {
                case "nc":
                    mediaType = MediaType.APPLICATION_OCTET_STREAM;
                    break;
                case "png":
                    mediaType = MediaType.IMAGE_PNG;
                    break;
                case "tiff":
                    mediaType = MediaType.APPLICATION_OCTET_STREAM;
                    break;
                case "jpeg":
                    mediaType = MediaType.IMAGE_JPEG;
                    break;
                default:
                    break;
            }
            return ResponseEntity.ok().contentType(mediaType)
                    .header(HttpHeaders.CONTENT_DISPOSITION,
                            "attachment; filename=\"" + resource.getFilename() + "\"")
                    .body(resource);
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseEntity.status(500).body(null);

        }
    }

    @Operation(summary = "删除文件", description = "根据id删除文件")
    @Parameters({ @Parameter(name = "id", description = "文件ID", required = true, example = "1") })
    @DeleteMapping("delete_file")
    public ResponseResult<Map<String, Object>> deleteFile(@RequestParam Integer id) {
        Map<String, Object> result = new HashMap<>();
        LayerData layerData = layerService.getById(id);
        if (layerData.getFileType().equals("nc")) {
            String storeName = layerData.getOriginName();
            if (storeName != null) {
                storeName = storeName.substring(0, storeName.lastIndexOf(".nc"));
            }
            try {
                if (layerData.getIsPublished()) {
                    layerService.deleteStore(storeName);
                } else {
                    layerService.removeById(id);
                    DirUtils.deleteDir(layerData.getSavedDir());
                }
                return ResponseResult.success("删除存储仓库成功", null);
            } catch (Exception e) {
                // TODO bug，删除存储仓库失败
                throw new RuntimeException("删除存储仓库失败: " + e.getMessage());
            }
        } else {
            try {
                boolean isDeleted = layerService.removeById(id);
                DirUtils.deleteDir(layerData.getSavedDir());
                if (isDeleted) {
                    result.put("msg", "删除文件成功");
                    result.put("code", 200);
                } else {
                    result.put("msg", "文件不存在或已被删除");
                    result.put("code", 404);
                }
            } catch (Exception e) {
                e.printStackTrace();
                result.put("msg", "删除文件失败");
                result.put("code", 500);
                result.put("data", e.getMessage());
                return ResponseResult.fail(result);
            }
        }
        return ResponseResult.success(result);
    }

    @PostMapping("/layerPubish")
    @Operation(summary = "发布图层(根据文件id)", description = "根据文件id发布图层")
    public ResponseResult<String> postMethodName(Integer id) {
        try {
            LayerData entity = layerService.getById(id);
            layerService.layerPublish(entity);
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseResult.fail("图层发布失败: " + e.getMessage());
        }
        return ResponseResult.success("图层发布成功");

    }

    @Operation(summary = "目录导入", description = "导入目录下的所有文件")
    @PostMapping("/dir_import")
    public ResponseResult<?> dirImport(@RequestBody String dir) {
        // 参数检验
        File directory = DirUtils.DirValidate(dir);
        // 遍历目录下的所有文件
        List<File> files = DirUtils.getFilesFromDir(directory);
        // files逐个导入
        HashMap<String, ArrayList<?>> result = directoryMonitorService.filesUploadHandler(files);
        
        return ResponseResult.success(result);
    }

    @Operation(summary = "字段查询", description = "查询字段的值")
    @GetMapping("/field_query")
    public ResponseResult<Set<String>> fieldQuery(@RequestParam String fieldName) {
        // TODO: 检查字段是否存在
        if (fieldName == null || fieldName.isEmpty()) {
            throw new IllegalArgumentException("Parameter 'fieldName' cannot be null or empty");
        }
        try {
            return ResponseResult.success("查询成功", layerService.fieldQuery(fieldName));
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseResult.fail("查询字段失败: " + e.getMessage());
        }
    }

}
